package com.wuuxiang.swagger.spring.boot.autoconfigure.config;

import java.util.List;
import java.util.Objects;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ui.ModelMap;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.wuuxiang.swagger.spring.boot.autoconfigure.properties.Swagger2Properties;

import io.swagger.annotations.ApiOperation;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;

@Configuration
@ConditionalOnBean(Swagger2Properties.class)
public class Swagger2AutoConfiguration {

	@Autowired
	private Swagger2Properties swagger2Properties;

	private Predicate<String> doFilteringRules() {
		// return Predicates.not(PathSelectors.regex("/error.*"));
		// return or(regex("/hello.*"),
		// regex("/rest/adxSspFinanceManagement.*"));//success
		return Predicates.not(Predicates.or(PathSelectors.regex("/error.*"), PathSelectors.regex("/actuator.*")));
	}

	private List<Parameter> buildGlobalOperationParametersFromSwaggerProperties(
            List<Swagger2Properties.GlobalOperationParameter> globalOperationParameters) {
        List<Parameter> parameters = Lists.newArrayList(); 
        if (Objects.isNull(globalOperationParameters)) {
            return parameters;
        }
        for (Swagger2Properties.GlobalOperationParameter globalOperationParameter : globalOperationParameters) {
        	parameters.add(this.getParameter(globalOperationParameter));
        }
        return parameters;
    }
	
	// 增加全局变量	
	private Parameter getParameter(Swagger2Properties.GlobalOperationParameter globalOperationParameter) {
		return new ParameterBuilder()
	        .name(globalOperationParameter.getName())
	        .description(globalOperationParameter.getDescription())
	        .modelRef(new ModelRef(globalOperationParameter.getModelRef()))
	        .parameterType(globalOperationParameter.getParameterType())
	        .required(Boolean.parseBoolean(globalOperationParameter.getRequired()))
	        .defaultValue(globalOperationParameter.getDefaultValue())
	        .build();
	}
	
	List<SecurityReference> defaultAuth() {
		AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
		AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
		authorizationScopes[0] = authorizationScope;
		return Lists.newArrayList(
			new SecurityReference("BearerToken", authorizationScopes)
			//,new SecurityReference("clientId", authorizationScopes)
			//,new SecurityReference("clientSecret", authorizationScopes)
			//,new SecurityReference("accessToken", authorizationScopes)
		);
	}
	  
	private List<SecurityContext> securityContexts() {
		return Lists.newArrayList(
			SecurityContext.builder()
			.securityReferences(defaultAuth())
			.forPaths(PathSelectors.regex("/*.*"))
			.build());
	}
	
	private List<ApiKey> securitySchemes() {
        return Lists.newArrayList(
                new ApiKey("BearerToken", "Authorization", "header")
                //,new ApiKey("clientId", "客户端ID", "header")
                //,new ApiKey("clientSecret", "客户端秘钥", "header")
                //,new ApiKey("accessToken", "客户端访问标识", "header")
        );
    }
	
	@Bean
	public Docket createRestApi() {
		// Predicate<RequestHandler> selector = RequestHandlerSelectors.any();
		Predicate<RequestHandler> selector = RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class);
		String basePackage = swagger2Properties.getBasePackage();
		if (StringUtils.isEmpty(basePackage)) {
			selector = RequestHandlerSelectors.basePackage(basePackage);
		}
		
		return new Docket(DocumentationType.SWAGGER_2).ignoredParameterTypes(ModelMap.class, BindingResult.class) // 忽略一些文档显示无意义的参数
				.apiInfo(apiInfo()).enable(swagger2Properties.getEnabled()).select().apis(selector)
				.paths(doFilteringRules()) // .paths(PathSelectors.any())
				.build()
				.globalOperationParameters(this.buildGlobalOperationParametersFromSwaggerProperties(swagger2Properties.getGlobalOperationParameters()))
				.securityContexts(securityContexts())
				.securitySchemes(securitySchemes());
	}

	private Contact contact() {
		return new Contact(swagger2Properties.getContact().getName(), 
				swagger2Properties.getContact().getUrl(),
				swagger2Properties.getContact().getEmail());
	}

	private ApiInfo apiInfo() {
		return new ApiInfoBuilder()
			.title(swagger2Properties.getTitle())
			.description(swagger2Properties.getDescription())
			.termsOfServiceUrl(swagger2Properties.getTermsOfServiceUrl())
			.version(swagger2Properties.getVersion())
			.contact(contact()).build();
	}

}
